package com.junxonline.instant.admin.service.device.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.junxonline.instant.admin.service.device.CommandService;
import com.junxonline.instant.common.annotation.DevicePushLog;
import com.junxonline.instant.common.constant.RedisConstant;
import com.junxonline.instant.common.constant.TerminalCommandMqConstant;
import com.junxonline.instant.common.entity.terminal.websocket.MessageFrame;
import com.junxonline.instant.common.enumeration.TerminalCommandEnum;
import com.junxonline.instant.common.util.common.RedisUtils;
import com.junxonline.instant.dao.entity.model.device.Terminal;
import com.junxonline.instant.dao.entity.model.terminal.TerminalDisplayType;
import com.junxonline.instant.dao.entity.model.terminal.TerminalVolume;
import com.junxonline.instant.dao.entity.vo.common.IdsVO;
import com.junxonline.instant.dao.entity.vo.device.command.SetDisplayTypeVO;
import com.junxonline.instant.dao.entity.vo.device.command.SetVolumeVO;
import com.junxonline.instant.dao.mapper.device.TerminalMapper;
import com.junxonline.instant.dao.mapper.terminal.TerminalDisplayTypeMapper;
import com.junxonline.instant.dao.mapper.terminal.TerminalVolumeMapper;
import com.junxonline.instant.rpc.terminal.TerminalSendMessageRpcService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * 终端指令接口实现类
 *
 * @author JunX
 * @date 2021-11-12
 */
@Service
@Transactional
public class CommandServiceImpl implements CommandService {

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private TerminalMapper terminalMapper;

    @Autowired
    private TerminalVolumeMapper terminalVolumeMapper;

    @Autowired
    private TerminalDisplayTypeMapper terminalDisplayTypeMapper;

    @DubboReference
    private TerminalSendMessageRpcService terminalSendMessageRpcService;

    /**
     * 设置音量
     *
     * @param vo 请求参数
     */
    @Override
    @DevicePushLog(type = TerminalCommandEnum.SET_VOLUME)
    public void setVolume(SetVolumeVO vo) {
        Map<String, Object> contentMap = new HashMap<>();
        contentMap.put("volume", vo.getVolume());
        // 先删除旧数据再插入新的数据
        for (Long id : vo.getIds()) {
            Terminal terminal = terminalMapper.selectById(id);
            String terminalCode = terminal.getCode();
            redisUtils.del(RedisConstant.KEY_TERMINAL_VOLUME + terminalCode);
            terminalVolumeMapper.delete(new LambdaUpdateWrapper<TerminalVolume>().eq(TerminalVolume::getTerminalCode, terminalCode));
            TerminalVolume terminalVolume = new TerminalVolume();
            terminalVolume.setTerminalCode(terminalCode);
            terminalVolume.setVolume(vo.getVolume());
            terminalVolumeMapper.insert(terminalVolume);
        }
        String destination = TerminalCommandMqConstant.TOPIC_SET_COMMAND + ":" + TerminalCommandMqConstant.TAG_SET_VOLUME;
        sendMessage(vo.getIds(), TerminalCommandEnum.SET_VOLUME.getValue(), destination, contentMap, true);
    }

    /**
     * 设置显示方式
     *
     * @param vo 请求参数
     */
    @Override
    @DevicePushLog(type = TerminalCommandEnum.SET_DISPLAY_TYPE)
    public void setDisplayType(SetDisplayTypeVO vo) {
        Map<String, Object> contentMap = new HashMap<>();
        contentMap.put("displayType", vo.getDisplayType());
        // 先删除旧数据再插入新的数据
        for (Long id : vo.getIds()) {
            Terminal terminal = terminalMapper.selectById(id);
            String terminalCode = terminal.getCode();
            redisUtils.del(RedisConstant.KEY_TERMINAL_DISPLAY_TYPE + terminalCode);
            terminalDisplayTypeMapper.delete(new LambdaUpdateWrapper<TerminalDisplayType>().eq(TerminalDisplayType::getTerminalCode, terminalCode));
            TerminalDisplayType terminalDisplayType = new TerminalDisplayType();
            terminalDisplayType.setTerminalCode(terminalCode);
            terminalDisplayType.setDisplayType(vo.getDisplayType());
            terminalDisplayTypeMapper.insert(terminalDisplayType);
        }
        String destination = TerminalCommandMqConstant.TOPIC_SET_COMMAND + ":" + TerminalCommandMqConstant.TAG_SET_DISPLAY_TYPE;
        sendMessage(vo.getIds(), TerminalCommandEnum.SET_DISPLAY_TYPE.getValue(), destination, contentMap, true);
    }

    /**
     * 拉取音量
     *
     * @param vo 请求参数
     */
    @Override
    @DevicePushLog(type = TerminalCommandEnum.QUERY_VOLUME)
    public void queryVolume(IdsVO<List<Long>> vo) {
        String destination = TerminalCommandMqConstant.TOPIC_QUERY_COMMAND + ":" + TerminalCommandMqConstant.TAG_QUERY_VOLUME;
        sendMessage(vo.getIds(), TerminalCommandEnum.QUERY_VOLUME.getValue(), destination, null, false);
    }

    /**
     * 拉取显示方式
     *
     * @param vo 请求参数
     */
    @Override
    @DevicePushLog(type = TerminalCommandEnum.QUERY_DISPLAY_TYPE)
    public void queryDisplayType(IdsVO<List<Long>> vo) {
        String destination = TerminalCommandMqConstant.TOPIC_QUERY_COMMAND + ":" + TerminalCommandMqConstant.TAG_QUERY_DISPLAY_TYPE;
        sendMessage(vo.getIds(), TerminalCommandEnum.QUERY_DISPLAY_TYPE.getValue(), destination, null, false);
    }

    /**
     * 拉取终端截屏
     *
     * @param vo 请求参数
     */
    @Override
    public void pullScreenshot(IdsVO<List<Long>> vo) {
        String destination = TerminalCommandMqConstant.TOPIC_QUERY_COMMAND + ":" + TerminalCommandMqConstant.TAG_PULL_SCREENSHOT;
        sendMessage(vo.getIds(), TerminalCommandEnum.PULL_SCREENSHOT.getValue(), destination, null, false);
    }

    /**
     * 发送消息
     *
     * @param ids         终端ID集合
     * @param type        消息类型
     * @param destination 目的地
     * @param contentMap  业务内容Map
     * @param isResend    是否需要重发
     */
    private void sendMessage(List<Long> ids, Integer type, String destination, Map<String, Object> contentMap, boolean isResend) {
        sendMessageRpc(ids, type, destination, contentMap, isResend);
    }

    /**
     * Rpc远程调用发送消息
     *
     * @param ids         终端ID集合
     * @param type        消息类型
     * @param destination 目的地
     * @param contentMap  业务内容Map
     * @param isResend    是否需要重发
     */
    private void sendMessageRpc(List<Long> ids, Integer type, String destination, Map<String, Object> contentMap, boolean isResend) {
        List<Terminal> terminals = terminalMapper.selectList(new LambdaQueryWrapper<Terminal>().in(Terminal::getId, ids));
        for (Terminal terminal : terminals) {
            String terminalCode = terminal.getCode();
            Map<String, Object> data = new HashMap<>();
            data.put("terminalCode", terminalCode);
            data.put("isResend", isResend);
            data.put("msg", new MessageFrame<>(UUID.randomUUID().toString(), DateUtil.current(), type, contentMap));
            terminalSendMessageRpcService.sendMessage(destination, JSON.toJSONString(data));
        }
    }

}
